#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <signal.h>
#include <sys/select.h>

// -------------------------- 1. 基础配置与结构定义（全局可见） --------------------------
// 基础配置
#define PORT 65201
#define MAX_CLIENTS 5
#define BUFFER_SIZE 256
#define INPUT_BUF_SIZE 1024
#define THREAD_POOL_SIZE 3  // 线程池大小
#define TASK_QUEUE_SIZE 10  // 任务队列容量

// 任务队列节点
typedef struct TaskNode {
    int client_sockfd;
    struct sockaddr_in client_addr;
    struct TaskNode *next;
} TaskNode;

// 任务队列（线程安全）
typedef struct {
    TaskNode *front;
    TaskNode *rear;
    int size;
    pthread_mutex_t mutex;
    pthread_cond_t not_empty;
    pthread_cond_t not_full;
} TaskQueue;

// 客户端管理结构体
typedef struct {
    int sockfd;
    char ip[INET_ADDRSTRLEN];
    int port;
    int is_connected;
    pthread_mutex_t send_mutex;
} Client;

// 全局变量
static Client clients[MAX_CLIENTS] = {0};
static pthread_mutex_t clients_mutex = PTHREAD_MUTEX_INITIALIZER;
static volatile int server_running = 1;
static int server_sockfd = -1;
static TaskQueue task_queue;
static pthread_t pool_threads[THREAD_POOL_SIZE];
static pthread_t input_thread_tid;

// -------------------------- 2. 工具函数声明（模块化拆分） --------------------------
// 任务队列操作
static void task_queue_init(void);
static int task_queue_add(int client_sockfd, struct sockaddr_in client_addr);
static int task_queue_get(int *client_sockfd, struct sockaddr_in *client_addr);
static void task_queue_destroy(void);

// 客户端管理
static void client_array_init(void);
static int find_free_client_slot(void);
static void remove_client(int slot_idx);
static int send_to_client(int slot_idx, const char *msg);

// 线程逻辑
static void *worker_thread(void *arg);
static void *terminal_input_thread(void *arg);

// 初始化与清理
static int server_socket_init(void);
static int thread_pool_init(void);
static void signal_handler_init(void);
static void server_resources_cleanup(void);

// 信号处理函数
static void sig_handler(int sig);


// -------------------------- 3. 工具函数实现（任务队列+客户端管理） --------------------------
/**
 * 任务队列初始化
 */
static void task_queue_init(void) {
    task_queue.front = NULL;
    task_queue.rear = NULL;
    task_queue.size = 0;
    pthread_mutex_init(&task_queue.mutex, NULL);
    pthread_cond_init(&task_queue.not_empty, NULL);
    pthread_cond_init(&task_queue.not_full, NULL);
}

// 任务队列添加任务
 

static int task_queue_add(int client_sockfd, struct sockaddr_in client_addr) {
    pthread_mutex_lock(&task_queue.mutex);

    // 队列满时等待
    while (task_queue.size >= TASK_QUEUE_SIZE && server_running) {
        pthread_cond_wait(&task_queue.not_full, &task_queue.mutex);
    }
    if (!server_running) {
        pthread_mutex_unlock(&task_queue.mutex);
        return -1;
    }

    // 创建任务节点
    TaskNode *new_node = (TaskNode *)malloc(sizeof(TaskNode));
    if (new_node == NULL) {
        perror("malloc TaskNode failed");
        pthread_mutex_unlock(&task_queue.mutex);
        return -1;
    }
    new_node->client_sockfd = client_sockfd;
    new_node->client_addr = client_addr;
    new_node->next = NULL;

    // 加入队列
    if (task_queue.rear == NULL) {
        task_queue.front = new_node;
        task_queue.rear = new_node;
    } else {
        task_queue.rear->next = new_node;
        task_queue.rear = new_node;
    }
    task_queue.size++;

    pthread_cond_signal(&task_queue.not_empty);
    pthread_mutex_unlock(&task_queue.mutex);
    return 0;
}

/**
 * 任务队列取出任务
 */
static int task_queue_get(int *client_sockfd, struct sockaddr_in *client_addr) {
    pthread_mutex_lock(&task_queue.mutex);

    // 队列空时等待
    while (task_queue.size == 0 && server_running) {
        pthread_cond_wait(&task_queue.not_empty, &task_queue.mutex);
    }
    if (!server_running) {
        pthread_mutex_unlock(&task_queue.mutex);
        return -1;
    }

    // 取出队首任务
    TaskNode *temp = task_queue.front;
    *client_sockfd = temp->client_sockfd;
    *client_addr = temp->client_addr;

    task_queue.front = temp->next;
    if (task_queue.front == NULL) {
        task_queue.rear = NULL;
    }
    task_queue.size--;
    free(temp);

    pthread_cond_signal(&task_queue.not_full);
    pthread_mutex_unlock(&task_queue.mutex);
    return 0;
}

/**
 * 任务队列销毁
 */
static void task_queue_destroy(void) {
    pthread_mutex_lock(&task_queue.mutex);
    TaskNode *temp = task_queue.front;
    while (temp != NULL) {
        TaskNode *next = temp->next;
        free(temp);
        temp = next;
    }
    task_queue.front = NULL;
    task_queue.rear = NULL;
    task_queue.size = 0;
    pthread_mutex_unlock(&task_queue.mutex);

    pthread_mutex_destroy(&task_queue.mutex);
    pthread_cond_destroy(&task_queue.not_empty);
    pthread_cond_destroy(&task_queue.not_full);
}

/**
 * 客户端数组初始化
 */
static void client_array_init(void) {
    for (int i = 0; i < MAX_CLIENTS; i++) {
        clients[i].sockfd = -1;
        clients[i].is_connected = 0;
        memset(clients[i].ip, 0, sizeof(clients[i].ip));
        clients[i].port = 0;
        pthread_mutex_init(&clients[i].send_mutex, NULL);
    }
}

/**
 * 查找空闲客户端槽位
 */
static int find_free_client_slot(void) {
    pthread_mutex_lock(&clients_mutex);
    for (int i = 0; i < MAX_CLIENTS; i++) {
        if (clients[i].is_connected == 0) {
            pthread_mutex_unlock(&clients_mutex);
            return i;
        }
    }
    pthread_mutex_unlock(&clients_mutex);
    return -1;
}

/**
 * 移除客户端
 */
static void remove_client(int slot_idx) {
    pthread_mutex_lock(&clients_mutex);
    if (slot_idx >= 0 && slot_idx < MAX_CLIENTS && clients[slot_idx].is_connected) {
        close(clients[slot_idx].sockfd);
        clients[slot_idx].is_connected = 0;
        clients[slot_idx].sockfd = -1;
        printf("[%s:%d] 客户端已移除\n", clients[slot_idx].ip, clients[slot_idx].port);
        pthread_mutex_destroy(&clients[slot_idx].send_mutex);
    }
    pthread_mutex_unlock(&clients_mutex);
}

/**
 * 向指定客户端发送消息
 */
static int send_to_client(int slot_idx, const char *msg) {
    if (slot_idx < 0 || slot_idx >= MAX_CLIENTS) return -1;

    pthread_mutex_lock(&clients_mutex);
    if (clients[slot_idx].is_connected == 0) {
        pthread_mutex_unlock(&clients_mutex);
        printf("发送失败：客户端[%d]已断开\n", slot_idx);
        return -1;
    }
    pthread_mutex_lock(&clients[slot_idx].send_mutex);
    pthread_mutex_unlock(&clients_mutex);

    ssize_t send_len = send(clients[slot_idx].sockfd, msg, strlen(msg), 0);
    if (send_len == -1) {
        perror("send_to_client 失败");
        pthread_mutex_unlock(&clients[slot_idx].send_mutex);
        return -1;
    }

    pthread_mutex_unlock(&clients[slot_idx].send_mutex);
    return 0;
}

// -------------------------- 4. 线程逻辑实现（工作线程+输入线程） --------------------------
/**
 * 线程池工作线程：处理客户端消息
 */
static void *worker_thread(void *arg) {
    (void)arg;
    int client_sockfd;
    struct sockaddr_in client_addr;

    while (server_running) {
        // 从任务队列取任务
        if (task_queue_get(&client_sockfd, &client_addr) != 0) {
            continue;
        }

        // 分配客户端槽位
        int slot_idx = find_free_client_slot();
        if (slot_idx == -1) {
            printf("客户端已满，拒绝新连接\n");
            close(client_sockfd);
            continue;
        }
        pthread_mutex_lock(&clients_mutex);
        clients[slot_idx].sockfd = client_sockfd;
        clients[slot_idx].is_connected = 1;
        inet_ntop(AF_INET, &client_addr.sin_addr, clients[slot_idx].ip, sizeof(clients[slot_idx].ip));
        clients[slot_idx].port = ntohs(client_addr.sin_port);
        pthread_mutex_unlock(&clients_mutex);

        printf("[%s:%d] 客户端连接成功（工作线程ID: %ld）\n", 
               clients[slot_idx].ip, clients[slot_idx].port, pthread_self());

        // 处理客户端消息
        char recv_buf[BUFFER_SIZE];
        fd_set read_fds;
        struct timeval tv;
        while (server_running && clients[slot_idx].is_connected) {
            FD_ZERO(&read_fds);
            FD_SET(client_sockfd, &read_fds);
            tv.tv_sec = 1;
            tv.tv_usec = 0;

            int ret = select(client_sockfd + 1, &read_fds, NULL, NULL, &tv);
            if (ret < 0) {
                if (server_running == 0) break;
                perror("select 失败");
                continue;
            } else if (ret == 0) {
                continue;
            }

            // 读取消息
            memset(recv_buf, 0, sizeof(recv_buf));
            ssize_t recv_len = recv(client_sockfd, recv_buf, sizeof(recv_buf) - 1, 0);
            
            printf("[%s:%d] 收到消息: %s\n", clients[slot_idx].ip, clients[slot_idx].port, recv_buf);

            // 自动同意聊天申请
            if (strncmp(recv_buf, "APPLY:人工聊天申请", 16) == 0) {
                const char *reply = "APPLY_REPLY:yes";
                if (send_to_client(slot_idx, reply) == 0) {
                    printf("[%s:%d] 已自动同意人工聊天申请\n", clients[slot_idx].ip, clients[slot_idx].port);
                }
            }
            // 消息回声
            else {
                if (send_to_client(slot_idx, recv_buf) != 0) {
                    printf("[%s:%d] 回声消息发送失败\n", clients[slot_idx].ip, clients[slot_idx].port);
                }
            }
        }

        // 清理客户端资源
        remove_client(slot_idx);
        printf("[%s:%d] 客户端处理结束（工作线程ID: %ld）\n", 
               clients[slot_idx].ip, clients[slot_idx].port, pthread_self());
    }
    return NULL;
}

/**
 * 终端输入线程：处理list/reply/exit命令
 */
static void *terminal_input_thread(void *arg) {
    (void)arg;
    char input_buf[INPUT_BUF_SIZE];
    printf("\n=== 终端操作说明 ===\n");
    printf("1. 输入 'list' 查看在线客户端\n");
    printf("2. 输入 'reply 客户端索引 消息' 回复指定客户端（例：reply 0 你好）\n");
    printf("3. 输入 'exit' 关闭服务器\n");
    printf("====================\n");

    while (server_running) {
        printf("\n请输入操作: ");
        if (fgets(input_buf, sizeof(input_buf), stdin) == NULL) break;

        input_buf[strcspn(input_buf, "\n")] = 0;
        if (strlen(input_buf) == 0) continue;

        // 退出服务器
        if (strcmp(input_buf, "exit") == 0) {
            server_running = 0;
            printf("正在关闭服务器...\n");
            close(server_sockfd);
            pthread_cond_broadcast(&task_queue.not_empty);  // 唤醒工作线程
            break;
        }
        // 查看在线客户端
        else if (strcmp(input_buf, "list") == 0) {
            pthread_mutex_lock(&clients_mutex);
            printf("\n=== 在线客户端列表 ===\n");
            int online_count = 0;
            for (int i = 0; i < MAX_CLIENTS; i++) {
                if (clients[i].is_connected) {
                    printf("索引 %d: IP=%s 端口=%d\n", i, clients[i].ip, clients[i].port);
                    online_count++;
                }
            }
            if (online_count == 0) printf("暂无在线客户端\n");
            printf("====================\n");
            pthread_mutex_unlock(&clients_mutex);
        }
        // 回复客户端
        else if (strncmp(input_buf, "reply ", 6) == 0) {
            char *cmd = input_buf + 6;
            char *slot_str = strtok(cmd, " ");
            char *msg = strtok(NULL, "");
            if (slot_str == NULL || msg == NULL) {
                printf("格式错误！正确格式：reply 客户端索引 消息（例：reply 0 你好）\n");
                continue;
            }

            int slot_idx = atoi(slot_str);
            pthread_mutex_lock(&clients_mutex);
            if (slot_idx < 0 || slot_idx >= MAX_CLIENTS || clients[slot_idx].is_connected == 0) {
                pthread_mutex_unlock(&clients_mutex);
                printf("客户端索引 %d 无效或已断开\n", slot_idx);
                continue;
            }
            char client_ip[INET_ADDRSTRLEN];
            strncpy(client_ip, clients[slot_idx].ip, sizeof(client_ip) - 1);
            int client_port = clients[slot_idx].port;
            pthread_mutex_unlock(&clients_mutex);

            // 发送回复消息
            char chat_msg[BUFFER_SIZE];
            snprintf(chat_msg, sizeof(chat_msg), "CHAT:%s", msg);
            if (send_to_client(slot_idx, chat_msg) == 0) {
                printf("已向 [%s:%d] 发送消息: %s\n", client_ip, client_port, msg);
            }
        }
        // 未知命令
        else {
            printf("未知命令！输入 'list' 查看帮助\n");
        }
    }
    return NULL;
}

// -------------------------- 5. 初始化与清理函数实现 --------------------------
/**
 * 服务器socket初始化（创建+绑定+监听）
 */
static int server_socket_init(void) {
    // 创建socket
    server_sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (server_sockfd == -1) {
        perror("创建服务器socket失败");
        return -1;
    }

    // 端口复用
    int opt = 1;
    if (setsockopt(server_sockfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == -1) {
        perror("设置socket选项失败");
        close(server_sockfd);
        return -1;
    }

    // 绑定地址
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons(PORT);
    server_addr.sin_addr.s_addr = INADDR_ANY;
    if (bind(server_sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {
        perror("绑定端口失败");
        close(server_sockfd);
        return -1;
    }

    // 监听
    if (listen(server_sockfd, MAX_CLIENTS) == -1) {
        perror("监听失败");
        close(server_sockfd);
        return -1;
    }

    printf("服务器启动成功，监听端口 %d...\n", PORT);
    return 0;
}

/**
 * 线程池初始化（创建工作线程+输入线程）
 */
static int thread_pool_init(void) {
    // 初始化任务队列
    task_queue_init();

    // 创建工作线程
    for (int i = 0; i < THREAD_POOL_SIZE; i++) {
        if (pthread_create(&pool_threads[i], NULL, worker_thread, NULL) != 0) {
            perror("创建工作线程失败");
            // 回滚已创建的线程
            for (int j = 0; j < i; j++) {
                pthread_cancel(pool_threads[j]);
                pthread_join(pool_threads[j], NULL);
            }
            task_queue_destroy();
            return -1;
        }
        pthread_detach(pool_threads[i]);  // 分离线程，自动回收
    }

    // 创建终端输入线程
    if (pthread_create(&input_thread_tid, NULL, terminal_input_thread, NULL) != 0) {
        perror("创建终端输入线程失败");
        // 回滚工作线程
        for (int i = 0; i < THREAD_POOL_SIZE; i++) {
            pthread_cancel(pool_threads[i]);
        }
        task_queue_destroy();
        return -1;
    }

    printf("线程池初始化完成，工作线程数量：%d\n", THREAD_POOL_SIZE);
    return 0;
}

/**
 * 信号处理函数（用于优雅退出）
 */
static void sig_handler(int sig) {
    (void)sig;
    if (server_running) {
        printf("\n收到中断信号，正在关闭服务器...\n");
        server_running = 0;
        close(server_sockfd);
        pthread_cond_broadcast(&task_queue.not_empty);  // 唤醒所有工作线程
    }
}

/**
 * 信号处理初始化（Ctrl+C优雅退出）
 */
static void signal_handler_init(void) {
    signal(SIGPIPE, SIG_IGN);  // 忽略管道破裂信号
    signal(SIGINT, sig_handler); // 使用标准signal函数注册信号处理函数
}

/**
 * 服务器资源清理（客户端+任务队列+锁）
 */
static void server_resources_cleanup(void) {
    // 关闭客户端连接
    for (int i = 0; i < MAX_CLIENTS; i++) {
        if (clients[i].is_connected) {
            close(clients[i].sockfd);
            pthread_mutex_destroy(&clients[i].send_mutex);
        }
    }

    // 销毁任务队列
    task_queue_destroy();

    // 销毁客户端全局锁
    pthread_mutex_destroy(&clients_mutex);

    // 关闭服务器socket
    if (server_sockfd != -1) {
        close(server_sockfd);
    }

    printf("服务器已完全关闭\n");
}

// -------------------------- 6. main --------------------------
int main() {
    // 1. 初始化核心模块
    client_array_init();          // 初始化客户端数组
    if (server_socket_init() != 0) {  // 初始化服务器socket
        return EXIT_FAILURE;
    }
    signal_handler_init();        // 初始化信号处理
    if (thread_pool_init() != 0) {    // 初始化线程池
        close(server_sockfd);
        return EXIT_FAILURE;
    }

    // 2. 主线程：接受客户端连接，添加到任务队列
    struct sockaddr_in client_addr;
    socklen_t client_addr_len = sizeof(client_addr);
    while (server_running) {
        int client_sockfd = accept(server_sockfd, (struct sockaddr*)&client_addr, &client_addr_len);
        if (client_sockfd == -1) {
            if (server_running == 0) break;  // 服务器关闭时退出
            perror("接受客户端连接失败");
            continue;
        }

        // 将客户端连接添加到任务队列
        if (task_queue_add(client_sockfd, client_addr) != 0) {
            close(client_sockfd);
            printf("任务队列已满，拒绝客户端连接\n");
        }
    }

    // 3. 等待输入线程退出，清理资源
    pthread_join(input_thread_tid, NULL);
    server_resources_cleanup();

    return EXIT_SUCCESS;
}